<template>
  <div class="flow-graph" :class="{ 'show-legend': config.showLegend }">
    <!-- 画布容器 -->
    <div class="flow-container" ref="containerRef">
      <div class="flow-canvas" :style="canvasStyle">
        <!-- 渲染节点 -->
        <FlowNode
          v-for="node in layoutNodes"
          :key="node.id"
          :node="node"
          :is-selected="selectedNodeId === node.id"
          @click="handleNodeClick"
        >
          <!-- 传递插槽 -->
          <template #default="slotProps">
            <slot name="node" v-bind="slotProps" />
          </template>
          <template #icon="slotProps">
            <slot name="node-icon" v-bind="slotProps" />
          </template>
          <template #content="slotProps">
            <slot name="node-content" v-bind="slotProps" />
          </template>
        </FlowNode>
        
        <!-- 渲染连接线 -->
        <FlowConnection
          v-for="edge in layoutEdges"
          :key="edge.id"
          :edge="edge"
          @click="handleEdgeClick"
        />
      </div>
    </div>
    
    <!-- 空状态 -->
    <div v-if="layoutNodes.length === 0" class="empty-state">
      <div class="empty-icon">
        <svg width="48" height="48" viewBox="0 0 48 48" fill="currentColor">
          <circle cx="24" cy="24" r="20" fill="none" stroke="currentColor" stroke-width="2" />
          <circle cx="24" cy="24" r="4" />
        </svg>
      </div>
      <p>{{ emptyText }}</p>
    </div>
    
    <!-- 图例 -->
    <div v-if="config.showLegend && layoutNodes.length > 0" class="flow-legend">
      <div
        v-for="(item, type) in CONNECTION_TYPES"
        :key="type"
        class="legend-item"
      >
        <div class="legend-line-simple" :style="getLegendLineStyle(type)"></div>
        <span>{{ item.label }}</span>
      </div>
    </div>
  </div>
</template>

<script>
import { ref, reactive, computed, watch, onMounted, onUnmounted, nextTick } from 'vue';
import FlowNode from './FlowNode.vue';
import FlowConnection from './FlowConnection.vue';
import { parseNodeIds, calculateNodeLevels, groupNodesByLevel, getConnectionType } from './utils';
import { DEFAULT_CONFIG, CONNECTION_TYPES, MIN_CANVAS_SIZE } from './constants';

export default {
  name: 'FlowGraph',
  components: {
    FlowNode,
    FlowConnection,
  },
  props: {
    // 节点数据
    nodes: {
      type: Array,
      default: () => [],
    },
    // 配置项
    config: {
      type: Object,
      default: () => ({}),
    },
    // 空状态文本
    emptyText: {
      type: String,
      default: '暂无数据',
    },
  },
  emits: ['node-click', 'edge-click', 'layout-complete'],
  setup(props, { emit }) {
    const containerRef = ref(null);
    const selectedNodeId = ref('');
    
    // 合并配置
    const mergedConfig = computed(() => ({
      ...DEFAULT_CONFIG,
      ...props.config,
    }));
    
    // 画布配置
    const canvasConfig = reactive({
      width: MIN_CANVAS_SIZE.width,
      height: MIN_CANVAS_SIZE.height,
    });
    
    // 画布样式
    const canvasStyle = computed(() => ({
      width: `${canvasConfig.width}px`,
      height: `${canvasConfig.height}px`,
      minWidth: '100%',
      minHeight: '100%',
    }));
    
    // 布局后的节点
    const layoutNodes = ref([]);
    
    // 布局后的边
    const layoutEdges = ref([]);
    
    /**
     * 计算节点布局
     */
    const calculateLayout = () => {
      if (!props.nodes || props.nodes.length === 0) {
        layoutNodes.value = [];
        layoutEdges.value = [];
        updateCanvasSize();
        return;
      }
      
      const config = mergedConfig.value;
      const nodeMap = new Map();
      
      // 1. 解析节点关系
      props.nodes.forEach(node => {
        const preIds = parseNodeIds(node.preNodeIds);
        const nextIds = parseNodeIds(node.nextNodeIds);
        
        nodeMap.set(node.id, {
          ...node,
          preNodeIds: preIds,
          nextNodeIds: nextIds,
          level: -1,
          row: 0,
          inDegree: preIds.length,
        });
      });
      
      // 2. 拓扑排序计算层级
      calculateNodeLevels(nodeMap);
      
      // 3. 按层级分组
      const levelGroups = groupNodesByLevel(nodeMap);
      
      // 4. 为每层节点分配行位置
      levelGroups.forEach((nodeIds) => {
        nodeIds.forEach((id, index) => {
          const node = nodeMap.get(id);
          node.row = index;
        });
      });
      
      // 5. 计算最大行数
      const maxRowsInLevel = Math.max(
        1,
        ...Array.from(levelGroups.values()).map(ids => ids.length)
      );
      
      // 6. 布局节点
      const nodes = [];
      nodeMap.forEach((nodeData, id) => {
        const levelNodes = levelGroups.get(nodeData.level) || [];
        const nodesInLevel = levelNodes.length;
        
        // 垂直居中
        const totalHeight = (nodesInLevel - 1) * config.verticalSpacing + config.nodeHeight;
        const startY = config.padding + Math.max(0, (maxRowsInLevel * config.verticalSpacing - totalHeight) / 2);
        
        nodes.push({
          ...nodeData,
          x: config.padding + nodeData.level * config.horizontalSpacing,
          y: startY + nodeData.row * config.verticalSpacing,
          width: config.nodeWidth,
          height: config.nodeHeight,
          hasInput: nodeData.preNodeIds.length > 0,
          hasOutput: nodeData.nextNodeIds.length > 0,
        });
      });
      
      layoutNodes.value = nodes;
      
      // 7. 计算连接线
      calculateEdges();
      
      // 8. 更新画布大小
      updateCanvasSize();
      
      // 9. 触发布局完成事件
      emit('layout-complete', {
        nodes: layoutNodes.value,
        edges: layoutEdges.value,
      });
    };
    
    /**
     * 计算节点连接点的Y坐标
     * @param {Object} node - 节点对象（包含 x, y, width, height）
     * @param {Number} connectionCount - 连接总数
     * @param {Number} connectionIndex - 当前连接的索引（0-based）
     * @returns {Number} - 连接点的绝对Y坐标
     */
    const getConnectionPointY = (node, connectionCount, connectionIndex) => {
      // 单个连接：使用节点中心点
      if (connectionCount === 1) {
        return node.y + node.height / 2;
      }
      
      // 多个连接：在节点高度的 20%-80% 范围内均匀分布
      const usableRatio = 0.6;  // 使用节点高度的60%
      const startRatio = 0.2;    // 从20%位置开始
      
      if (connectionCount === 2) {
        // 2个连接：分别在 20% 和 80% 位置
        return node.y + node.height * (startRatio + connectionIndex * usableRatio);
      }
      
      // 3个或更多连接：在20%-80%范围内均匀分布
      const spacing = usableRatio / (connectionCount - 1);
      return node.y + node.height * (startRatio + connectionIndex * spacing);
    };
    
    /**
     * 计算连接线
     * 基于节点的实际位置和连接关系，计算每条连接线的起点和终点坐标
     */
    const calculateEdges = () => {
      const edges = [];
      
      layoutNodes.value.forEach(fromNode => {
        // 跳过没有输出的节点
        if (!fromNode.nextNodeIds || fromNode.nextNodeIds.length === 0) {
          return;
        }
        
        // 对输出节点ID排序，确保连接点分配的一致性
        const sortedNextIds = [...fromNode.nextNodeIds].sort();
        const outputCount = sortedNextIds.length;
        
        sortedNextIds.forEach((nextId, outputIndex) => {
          const toNode = layoutNodes.value.find(n => n.id === nextId);
          
          if (!toNode) {
            return;
          }
          
          // === 计算起点（fromNode的右侧边缘）===
          const startX = fromNode.x + fromNode.width;
          const startY = getConnectionPointY(fromNode, outputCount, outputIndex);
          
          // === 计算终点（toNode的左侧边缘）===
          // 找到所有指向toNode的节点
          const incomingNodes = layoutNodes.value.filter(n => 
            n.nextNodeIds && n.nextNodeIds.includes(toNode.id)
          );
          
          // 对输入节点ID排序，确保连接点分配的一致性
          const sortedIncomingIds = incomingNodes.map(n => n.id).sort();
          const inputCount = sortedIncomingIds.length;
          const inputIndex = sortedIncomingIds.indexOf(fromNode.id);
          
          const endX = toNode.x;
          const endY = getConnectionPointY(toNode, inputCount, inputIndex);
          
          // === 创建连接线 ===
          const distance = Math.sqrt(
            Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2)
          );
          
          // 只创建有意义长度的连接线
          if (distance > 10) {
            edges.push({
              id: `edge-${fromNode.id}-${toNode.id}`,
              source: fromNode.id,
              target: toNode.id,
              type: getConnectionType(fromNode, toNode),
              startX,
              startY,
              endX,
              endY,
            });
          }
        });
      });
      
      layoutEdges.value = edges;
    };
    
    /**
     * 更新画布大小
     */
    const updateCanvasSize = () => {
      if (layoutNodes.value.length === 0) {
        canvasConfig.width = MIN_CANVAS_SIZE.width;
        canvasConfig.height = MIN_CANVAS_SIZE.height;
        return;
      }
      
      const config = mergedConfig.value;
      const maxX = Math.max(...layoutNodes.value.map(n => n.x + n.width));
      const maxY = Math.max(...layoutNodes.value.map(n => n.y + n.height));
      
      canvasConfig.width = Math.max(MIN_CANVAS_SIZE.width, maxX + config.padding);
      canvasConfig.height = Math.max(MIN_CANVAS_SIZE.height, maxY + config.padding);
    };
    
    /**
     * 节点点击处理
     */
    const handleNodeClick = ({ node, event }) => {
      selectedNodeId.value = node.id;
      emit('node-click', { node, event });
    };
    
    /**
     * 边点击处理
     */
    const handleEdgeClick = ({ edge, event }) => {
      emit('edge-click', { edge, event });
    };
    
    /**
     * 获取图例线条样式
     */
    const getLegendLineStyle = (type) => {
      const config = CONNECTION_TYPES[type];
      return {
        backgroundColor: config.color,
        height: `${config.lineWidth}px`,
      };
    };
    
    /**
     * 窗口大小变化处理
     */
    const handleResize = () => {
      if (mergedConfig.value.autoResize) {
        nextTick(() => {
          calculateLayout();
        });
      }
    };
    
    // 监听节点变化
    watch(
      () => props.nodes,
      () => {
        nextTick(() => {
          calculateLayout();
        });
      },
      { deep: true, immediate: true }
    );
    
    // 组件挂载
    onMounted(() => {
      if (mergedConfig.value.autoResize) {
        window.addEventListener('resize', handleResize);
      }
    });
    
    // 组件卸载
    onUnmounted(() => {
      if (mergedConfig.value.autoResize) {
        window.removeEventListener('resize', handleResize);
      }
    });
    
    return {
      containerRef,
      selectedNodeId,
      config: mergedConfig,
      canvasStyle,
      layoutNodes,
      layoutEdges,
      CONNECTION_TYPES,
      handleNodeClick,
      handleEdgeClick,
      getLegendLineStyle,
    };
  },
};
</script>

<style scoped>
.flow-graph {
  width: 100%;
  min-height: 320px;
  background-color: #f8f9fa;
  border-radius: 8px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  position: relative;
}

.flow-container {
  flex: 1;
  background: #ffffff;
  border-radius: 6px;
  border: 1px solid #e0e0e0;
  overflow: auto;
  position: relative;
  min-height: 200px;
}

.flow-canvas {
  position: relative;
  background-image: radial-gradient(circle, #f0f0f0 1px, transparent 1px);
  background-size: 15px 15px;
  background-position: 0 0;
}

/* 空状态 */
.empty-state {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #999;
  text-align: center;
  pointer-events: none;
}

.empty-icon {
  color: #ccc;
  margin-bottom: 12px;
}

.empty-state p {
  margin: 0;
  font-size: 14px;
}

/* 图例 */
.flow-legend {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding: 8px 12px;
  background: #f8f9fa;
  border-radius: 6px;
  margin-top: 8px;
  border: 1px solid #e0e0e0;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: #666;
}

.legend-line-simple {
  width: 30px;
  position: relative;
}

/* 响应式 */
@media (max-width: 768px) {
  .flow-graph {
    min-height: 240px;
    padding: 8px;
  }
  
  .flow-legend {
    flex-wrap: wrap;
    gap: 12px;
  }
}
</style>

